package com.njxxted.activiti.modules.process.extend.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.njxxted.activiti.common.constant.Constant;
import com.njxxted.activiti.common.util.JsonUtils;
import com.njxxted.activiti.common.util.StringUtils;
import com.njxxted.activiti.modules.base.service.BaseService;
import com.njxxted.activiti.modules.process.defintion.dao.ActRunDefinitionDao;
import com.njxxted.activiti.modules.process.defintion.entity.ActRunNodeConfigEntity;
import com.njxxted.activiti.modules.process.extend.dao.ExtendActHistoryDao;
import com.njxxted.activiti.modules.process.extend.entity.HistoryTaskInstanceEntity;
import com.njxxted.activiti.modules.process.extend.service.ExtendActHistoryService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.impl.persistence.entity.AttachmentEntityImpl;
import org.activiti.engine.impl.persistence.entity.UserEntityImpl;
import org.activiti.engine.task.Attachment;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * 描述：扩展流程实例历史表 service
 * <p>
 * 作者：HuTongFu
 * 邮箱：hu_tongfu@163.com
 * 时间：2019-08-12 16:58:12
 */
@Service("extendActHistoryService")
public class ExtendActHistoryServiceImpl extends BaseService implements ExtendActHistoryService {

    @Resource
    private ExtendActHistoryDao extendActHistoryDao;

    @Resource
    private HistoryService historyService;

    @Resource
    private TaskService taskService;

    @Resource
    private ActRunDefinitionDao actRunDefinitionDao;

    @Resource
    private IdentityService identityService;

    @Override
    public List<HistoryTaskInstanceEntity> getActTaskHistory(String instanceId) {
        List<HistoryTaskInstanceEntity> resList = Lists.newArrayList();
        List<HistoryTaskInstanceEntity> extendActHistoryEntities = extendActHistoryDao.queryObjectByPidTid(instanceId, null);
        ActRunNodeConfigEntity actRunNodeConfigEntity = new ActRunNodeConfigEntity();

        for (HistoryTaskInstanceEntity extendActHistoryEntity : extendActHistoryEntities) {
            List<Map<String, Object>> attachmentList = Lists.newCopyOnWriteArrayList();
            List<Attachment> taskAttachments = taskService.getTaskAttachments(extendActHistoryEntity.getTaskId());
            taskAttachments.parallelStream().forEachOrdered(attachment -> {
                AttachmentEntityImpl attachmentEntity = (AttachmentEntityImpl) attachment;
                String json = JsonUtils.beanToJson(attachmentEntity, "yyyy-MM-dd HH:mm:ss");
                attachmentList.add(JsonUtils.jsonToMap(json));
            });

            extendActHistoryEntity.setAttachments(attachmentList);
            resList.add(extendActHistoryEntity);
            // 查询出当前节点的配置信息
            actRunNodeConfigEntity.setRunTaskId(extendActHistoryEntity.getTaskId());
            List<ActRunNodeConfigEntity> configEntities = actRunDefinitionDao.getProcessDefinitionSettings(actRunNodeConfigEntity);
            // 过滤出只有候选人的配置项
            List<ActRunNodeConfigEntity> assignConfig = configEntities.parallelStream()
                    .filter(conf -> conf.getConfigType().contains("assign")).collect(Collectors.toList());

            // 匹配出符合条件的人员信息
            extendActHistoryEntity.setCandidateUsers(Lists.newArrayList(matchedUsers(extendActHistoryEntity.getInstanceId(), assignConfig)));
        }

        return resList;
    }


    /**
     * 转换 user为 map
     *
     * @return
     */
    private List<Map<String, String>> convertUser() {
        List<Map<String, String>> res = new CopyOnWriteArrayList<>();
        //查询出所有人员信息
        List<User> allUserList = identityService.createUserQuery().list();
        allUserList.parallelStream().forEachOrdered(user -> {
            UserEntityImpl uImpl = (UserEntityImpl) user;
            Map<String, String> map = Maps.newHashMap();
            List<Group> roleList = identityService.createGroupQuery().groupMember(user.getId()).groupType("role").list();
            List<Group> departList = identityService.createGroupQuery().groupMember(user.getId()).groupType("depart").list();
            String departIds = departList.parallelStream().map(Group::getId).collect(Collectors.joining(","));
            String roleIds = roleList.parallelStream().map(Group::getId).collect(Collectors.joining(","));
            map.put("id", uImpl.getId());
            map.put("head", uImpl.getPictureByteArrayRef().getId());
            map.put("roleId", roleIds);
            map.put("departId", departIds);
            map.put("name", uImpl.getLastName());
            map.put("type", "user");
            res.add(map);
        });
        return res;
    }

    /**
     * 匹配符合条件用户
     *
     * @param definitionSettings 流程配置信息
     * @param instanceId         流程实例id
     * @return
     */
    private Set<Map<String, String>> matchedUsers(String instanceId, List<ActRunNodeConfigEntity> definitionSettings) {
        Set<Map<String, String>> matchedUsers = new CopyOnWriteArraySet<>();
        //查询出流程发起人以及他所在的部门
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        String startUserId = instance.getStartUserId();
        List<Group> departs = identityService.createGroupQuery().groupType("depart").groupMember(startUserId).list();
        String departIds = departs.parallelStream().map(Group::getId).collect(Collectors.joining(","));
        // 匹配出符合条件的人员信息
        convertUser().parallelStream().forEachOrdered(user -> {
            StringBuilder stringBuilder = new StringBuilder();
            definitionSettings.parallelStream().forEachOrdered(setting -> {
                String otherValue = setting.getOtherValue();
                String[] arr = setting.getConfigValue().split("/");
                switch (setting.getConfigType()) {
                    case Constant.Flow.ASSIGN_USER:
                        stringBuilder.append(arr[arr.length - 1].equals(user.get("id"))).append(otherValue);
                        break;
                    case Constant.Flow.ASSIGN_DEPART:
                        stringBuilder.append(user.get("departId").contains(arr[arr.length - 1])).append(otherValue);
                        break;
                    case Constant.Flow.ASSIGN_ROLE:
                        stringBuilder.append(user.get("roleId").contains(arr[arr.length - 1])).append(otherValue);
                        break;
                    case Constant.Flow.ASSIGN_SPONSOR_DEPARTMENT:
                        stringBuilder.append(user.get("departId").contains(departIds)).append(otherValue);
                        break;
                }
            });
            String conditionStr = stringBuilder.toString();
            String replace = conditionStr.replace("and", " && ").replace("or", " || ");
            if (StringUtils.isTrue(replace)) {
                matchedUsers.add(user);
            }
        });
        return matchedUsers;
    }
}
